/** @jsxImportSource @emotion/react */
import { jsx, css } from "@emotion/react";
import * as React from "react";
import {CSSProperties, ReactNode, } from "react";
import {animated, useSprings} from "@react-spring/web";
import {useDrag} from "@use-gesture/react";
import {PanelEnlargeCtx, useMMenuBarOcup} from "./MainMenuBar";
import {DdMenu, DdMenuItem} from "./DropdownMenu";
import {IconChevronsLeft} from "./Icons";
import {MenuItem} from "./Menu";
import {useMeasure} from "./Hooks/use-measure";
import {useTheme} from "./Theme/Providers";


//React.HTMLAttributes<HTMLDivElement>
interface TwoHalfFrameProps  extends React.HTMLProps<HTMLDivElement>{
    children: React.ReactNode;
    //有半边的页面：详细操作页面。
    rightPanel: React.ReactNode;
    //切换Pager的两个页面
    //左半边 手机场景的 样式附加
    leftStyle?: CSSProperties;
    //右半边 手机场景的 样式附加
    rightStyle?: CSSProperties;
    //非轮播台的初始页面比例： 左边没有=0，1：左边右边1比2， 2： 1比1， 3： 2比1， 4：右边没有。
    enlarge?: number;
}

const ExternalThfpane = (props) => {
    return <div className='Thf_pane'
                css={{
                    overflowX: "hidden",     //右边页面可拉动往中间移动
                    overflowY: props.ix === 0 ? undefined : 'auto',
                    width: "100%",
                    height: "100%",
                    ...props.panStyle
                }}
                key={props.ix}
                tabIndex={props.index === props.ix ? 0 : -1}
    >
        {props.children}
    </div>
}
//必须再倒腾一手，不然编译报错了；
const ExternalFrmhalf = (props) => {
    return <div className={`Frm${props.index} ${props.ix === 0 ? "LeftP" : "RightP"}`}
                key={props.ix}
                style={{
                    position: "absolute",
                    display: "flex",
                    flexDirection: 'column',
                    flex: "none",
                    overflowY: 'auto',
                    overflowX: props.carousel ? undefined : "hidden",
                    top: 0,
                    bottom: 0,
                    left: props.ix === 0 ? 0 : props.carousel ? (props.index===1? 0 : "100%") : props.mobileList ? '100%' : `${props.leftpwp}%`,
                    right: 0,
                    opacity: props.carousel ? props.opacity : undefined,
                    transform: props.carousel ? (props.left.to ? props.left.to(x => clamp(x)).to(x => `translateX(${x}%)`) : undefined ) : undefined,
                    height: props.ix === 0 ? `calc(100vh - ${props.barHeight})` : props.carousel ? `calc(100vh - ${props.barHeight})` : '100vh',
                    width: props.ix === 0 ? ((props.carousel || props.mobileList) ? "100%" : `${props.leftpwp}%`) : (props.carousel ? "100%" : props.mobileList ? '0%' : `${100 - props.leftpwp}%`),
                }}
    >
        {props.children}
    </div>
}

/**公用框架组件  Left左半列表摘要 + 右半边Console详细操作的页面。手机窄屏变换为轮播。
 * 【注意】useContext(PanelEnlargeCtx);应该定义在TwoHalfFrame组件的层次顺序之下的，而不是TwoHalfFrame之前，否则PanelEnlargeCtx不正常。
 * TwoHalfFrame应该放在路由器每个路由顶部，外部加个PanelEnlargeCtx.Provider配套控制本实例TwoHalfFrame。
 * 本组件是框架，要配合 <TwoHalfRightPanel/>组件 以及<PanelEnlargeCtx.Provider 这两个东西来协同完成框架页面构建。
 * 需要在页面路由器头上加<PanelEnlargeCtx.Provider  value={{ enlarge, setEnlarge，activecas，setActivecas }}>
 * 【特别】<PanelEnlargeCtx.Provider的提供位置非常严格，可能无效:初始化取值，还是后来能修改赋值?。
 * 手机模式TwoHalfFrame右边页面实际和左边页面并排在X轴线，依据水平动画X变换移动来展示的。所以有些依据定位组件可能不适合右边页面会依附于左边页面的无效情况！
 * 【注意约束】两个半边页面状态变量不能交叉！两个页面需要独立分开，不能让左边页面的render直接导致右边页面的变动，否则会立刻切换到右边页面显示，同一个组件上用useMemo包裹。
 * */
export const TwoHalfFrame =
    ({
         children,
         rightPanel,
         leftStyle,
         rightStyle,
         enlarge: initEnlarge = 2,
         ref,
         ...other
     }: TwoHalfFrameProps
    ) => {
        const theme = useTheme();
        const {barHeight, bottomCss, carousel, isBigSrc, touchScr, mobileList} = useMMenuBarOcup(!rightPanel);
        const [enlarge, setEnlarge] = React.useState((!rightPanel && initEnlarge === 0) ? 2 : initEnlarge);

        const containerRef = React.useRef<HTMLDivElement>(null);
        const width = useMeasure(containerRef)?.width;
        // const x = useMotionValue(0);
        //正常轮播状态下默认优先看右边页面。
        const [index, setIndex] = React.useState(1);
        /*和布局相关的：手机书评模式情况下：transformX(0)实际是显示右半边页面的。transformX(containerRef.current?.clientWidth)实际是显示左半边页面的。
        * */
        // const calculateNewX = () =>
        //     (!carousel? 0 : index===1? 0 : -1) * (containerRef.current?.clientWidth || 0);

        //两个页面拼凑:
        const childrens = [children, rightPanel] as ReactNode[];

        // const handleNext = () => {
        //     setIndex(index===1 ? 0 : 1);
        // }
        // const handlePrev = () => {
        //     setIndex(index===0 ? 1 : 0);
        // }
        //外部也可以操纵，轮播台当前显示右边或左边。 【失败】注入Context实际有问题=导致ref.setActivecas()可能为undefined!
        // React.useImperativeHandle(ref, () => ({
        // }));

        const  getActivecas=() => {
            return (index===0? 1 : 0);
        }
        //无法直接用index对外替换Activecas？
        const setActivecas=(i: number) => {
            setIndex(i===0? 1 : 0);
        }
        //useLayoutEffect
        // React.useEffect(() => {
        //     x.set(0);
        //     //若用x.set(0);在autofoucus导致自动切换显示右边页面情况，无法正常。只好改成默认set(-1*?)
        //     x.stop();       //这个必须加上！
        //     const controls = animate(x, calculateNewX(), transition);
        //     return controls.stop
        // }, [carousel, containerRef.current?.clientWidth,  x])

        //已经默认，不需要外边initActivecas注入
        React.useEffect(() => {
            //轮播台 右边页面； #这里导致了：左边页面的render直接导致右边页面的变动，会立刻切换到右边页面显示。
            setIndex( 1);
        }, [rightPanel])
        //非手机轮播台模式的左右两半边页面宽度比例： 左边没有=0，1：左边右边1比2， 2： 1比1， 3： 2比1， 4：右边没有。
        const leftpwp= enlarge===0? 0 : (enlarge===1? 33.4 : (enlarge===4? 100 : (enlarge===3? 66.6 : 50)));
        //轮播形态的【页面组织】动画和隐藏。
        const [springs, setSprings] = useSprings(2, i => {
            return getAnimationValues(i, index);
        });

        React.useEffect(() => {
            setSprings(i => getAnimationValues(i, index));
        }, [index, setSprings])

        /*简易轮播台：只有左右两个页面，也不考虑嵌入在父辈轮播底下的需求。免去event.stopPropagation();
        动画采用transform，并且一步到位，中间拉拽没有体现｛left：0 100 -100｝没附加当前拉拽偏移量比例:体现两个半页面过渡各显示一部分的效果。
        真正页面移动还要通过setIndex+useEffect修正来执行，而不是动画直接跟随拉拽。
        * */
        const bind = useDrag((state) => {
                const { active, movement: [mx,my], direction: [xDir,yDir] , cancel,
                    swipe:[swpx,], last,  canceled,tap, event } = state;
                // console.log("框拉",state,"active",active,"last:",last,"tap",tap);
                // event.stopPropagation();     #不依靠direction[]swipe[]这两组有问题啊？
                if(!active && last && !canceled && !tap && (Math.abs(swpx)>0 || (Math.abs(mx)>=width*0.01 && Math.abs(mx)>Math.abs(my) ) ) ) {
                    let finalDir= swpx!==0? swpx : mx>0? 1 : -1;
                    //允许水平方向滑动
                    if(finalDir!==0){
                        setIndex(0===index? 1 : 0);
                        cancel();
                    }
                }
                //setSprings(i => getAnimationValues(i, index));
            },
            {
                swipe: {velocity: 0.01},
                filterTaps: true,
                pointer: {mouse: !touchScr },
                // pointer: {touch: true, mouse: !touchScr, },      //嵌套Pager拉拽避免拉动父辈层和search input的cancel在电脑模式点击能清空的要求正好冲突了。
                // triggerAllEvents: true,       //嵌套在另外一个Pager底下的Pager设置true。
                enabled: carousel,
            }
        );

        const AnimatedThfpane = animated(ExternalThfpane);
        const AnimatedFrmhalf = animated(ExternalFrmhalf);

        /*预定义style={{}}无法通过css={{}}样式参数来覆盖，只好全都放入css={{}}。
        把bind()提升到父辈层Div;不是儿子都有bind()多个状态机?;
        * */
        return (
            <PanelEnlargeCtx.Provider  value={{ enlarge, setEnlarge,
                setActivecas: setActivecas,  getActivecas: getActivecas,
            }}>
                <div  className="Thframe"
                      ref={containerRef}
                      {...bind()}
                      css={{
                          overflowX: carousel? "hidden" : undefined,
                          position: carousel? 'relative': 'static',
                          width: "100%",
                          height: "100vh",
                          touchAction: 'none',
                      }}
                      {...other}
                >
                    {
                        springs.map((props, i) => {
                            const  panStyle= i===0? leftStyle : rightStyle;
                            return (
                                <AnimatedFrmhalf key={i} index={index} ix={i} carousel={carousel} mobileList={mobileList}
                                                 leftpwp={leftpwp} opacity={props.opacity} left={props.left} barHeight={barHeight}
                                >
                                    <AnimatedThfpane index={index}  ix={i}  panStyle={panStyle}>
                                        {childrens[i]}
                                    </AnimatedThfpane>
                                </AnimatedFrmhalf>
                            );
                        })
                    }
                </div>

                { (!carousel && enlarge===4) &&
                    <div  className="Larger"
                          css={{
                              right: 0,
                              bottom: 0,
                              position: 'fixed',
                              zIndex: theme.zIndices.fixed
                          }}>
                        <DdMenu label="放大" tight={true}
                                icon={
                                    <MenuItem variant="ghost"  component={"div"}>
                                        <IconChevronsLeft />
                                    </MenuItem>
                                }
                        >
                            <DdMenuItem label="左满屏"
                                        onClick={(e) => {setEnlarge(4);}} />
                            <DdMenuItem label="1比2"
                                        onClick={(e) => {setEnlarge(1);}} />
                            <DdMenuItem label="1比1"
                                        onClick={(e) => {setEnlarge(2);}} />
                            <DdMenuItem label="2比1"
                                        onClick={(e) => {setEnlarge(3);}} />
                            <DdMenuItem label="右满屏"
                                        onClick={(e) => {setEnlarge(0);}} />
                        </DdMenu>
                    </div>
                }
            </PanelEnlargeCtx.Provider>
        );
    };

function getAnimationValues(i: number, currentIndex: number) {
    if(0===currentIndex){
        if(0===i)  return { left: 0, immediate: false, opacity: 1};
        else  return { left: 100, immediate: false, opacity: 0};
    }
    else{
        if(0===i)  return { left: -100, immediate: false, opacity: 0};
        else return { left: -100, immediate: false, opacity: 1};
    }
}
function clamp(x: number) {
    if (x > 50) {
        return 100;
    }
    if (x < -50) {
        return -100;
    }
    return x;
}


//路由动态加载的组件必须有default的
//export default TwoHalfFrame;
//使用<Tabs/》 <Stack/  </StackItem>组件进行的装配的实际还是同一个URL pathname,在里面点击切换其实还是局部视图切换，没有涉及到路由器，自然不会引起组件卸载和加载，算同一个大组件状态保留的。
